{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "SBoMk_Knl-D0"
   },
   "source": [
    "# Week 1: Working with time series\n",
    "\n",
    "Welcome! In this assignment you will be working with time series data. All of the data is going to be generated and you will implement several functions to split the data, create forecasts and evaluate the quality of those forecasts.\n",
    "\n",
    "\n",
    "#### TIPS FOR SUCCESSFUL GRADING OF YOUR ASSIGNMENT:\n",
    "\n",
    "- All cells are frozen except for the ones where you need to submit your solutions or when explicitly mentioned you can interact with it.\n",
    "- You can add new cells to experiment but these will be omitted by the grader, so don't rely on newly created cells to host your solution code, use the provided places for this.\n",
    "\n",
    "- You can add the comment # grade-up-to-here in any graded cell to signal the grader that it must only evaluate up to that point. This is helpful if you want to check if you are on the right track even if you are not done with the whole assignment. Be sure to remember to delete the comment afterwards!\n",
    "\n",
    "- Avoid using global variables unless you absolutely have to. The grader tests your code in an isolated environment without running all cells from the top. As a result, global variables may be unavailable when scoring your submission. Global variables that are meant to be used will be defined in UPPERCASE.\n",
    " \n",
    "- This assignment builds one block on top of the other, so it is very important that you pass all unittests before continuing to the next section, otherwise you might have issues grading your submission.\n",
    "\n",
    "- To submit your notebook, save it and then click on the blue submit button at the beginning of the page.\n",
    "\n",
    "Let's get started!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "id": "t9HrvPfrSlzS",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "import unittests"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "I-FvRlT_pzdB"
   },
   "source": [
    "The next cell includes a bunch of helper functions to generate and plot the time series:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "id": "ypWIppX9NlSy",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "def trend(time, slope=0):\n",
    "    \"\"\"A trend over time\"\"\"\n",
    "    return slope * time\n",
    "\n",
    "def seasonal_pattern(season_time):\n",
    "    \"\"\"Just an arbitrary pattern\"\"\"\n",
    "    return np.where(season_time < 0.1,\n",
    "                    np.cos(season_time * 7 * np.pi),\n",
    "                    1 / np.exp(5 * season_time))\n",
    "\n",
    "\n",
    "def seasonality(time, period, amplitude=1, phase=0):\n",
    "    \"\"\"Repeats the same pattern at each period\"\"\"\n",
    "    season_time = ((time + phase) % period) / period\n",
    "    return amplitude * seasonal_pattern(season_time)\n",
    "\n",
    "\n",
    "def noise(time, noise_level=1, seed=None):\n",
    "    \"\"\"Adds noise to the series\"\"\"\n",
    "    rnd = np.random.RandomState(seed)\n",
    "    return rnd.randn(len(time)) * noise_level\n",
    "\n",
    "\n",
    "def plot_series(time, series, format=\"-\", title=\"\", label=None, start=0, end=None):\n",
    "    \"\"\"Plot the series\"\"\"\n",
    "    plt.plot(time[start:end], series[start:end], format, label=label)\n",
    "    plt.xlabel(\"Time\")\n",
    "    plt.ylabel(\"Value\")\n",
    "    plt.title(title)\n",
    "    if label:\n",
    "        plt.legend()\n",
    "    plt.grid(True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generate time series data\n",
    "\n",
    "Using the previous functions, generate data that resembles a real-life time series.\n",
    "\n",
    "Notice that `TIME` represents the values in the x-coordinate while `SERIES` represents the values in the y-coordinate. This naming is used to avoid confusion with other kinds of data in which `x` and `y` have different meanings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 388
    },
    "deletable": false,
    "editable": false,
    "id": "urmjv7nzsP-h",
    "outputId": "43d6ca86-e23a-4039-b1b2-fb68585b9355",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# The time dimension or the x-coordinate of the time series\n",
    "TIME = np.arange(4 * 365 + 1, dtype=\"float32\")\n",
    "\n",
    "# Initial series is just a straight line with a y-intercept\n",
    "y_intercept = 10\n",
    "slope = 0.01\n",
    "SERIES = trend(TIME, slope) + y_intercept\n",
    "\n",
    "# Adding seasonality\n",
    "amplitude = 40\n",
    "SERIES += seasonality(TIME, period=365, amplitude=amplitude)\n",
    "\n",
    "# Adding some noise\n",
    "noise_level = 2\n",
    "SERIES += noise(TIME, noise_level, seed=42)\n",
    "\n",
    "# Plot the series\n",
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(TIME, SERIES)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is a good time to also define some useful global variables. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# Define time step to split the series\n",
    "SPLIT_TIME = 1100\n",
    "\n",
    "# Define the window size for forecasting later on\n",
    "WINDOW_SIZE = 50"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "UfdyqJJ1VZVu"
   },
   "source": [
    "### Exercise 1: train_val_split\n",
    "\n",
    "Now that you have the time series, let's split it so you can start forecasting.\n",
    "\n",
    "Complete the `train_val_split` function below which receives the `time` (x coordinate) and `series` (y coordinate) data. Notice that this value defaults to 1100 since this is an appropriate step to split the series into training and validation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "id": "utk866FUZEjU",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# GRADED FUNCTION: train_val_split\n",
    "def train_val_split(time, series):\n",
    "    \"\"\"Split time series into train and validation sets\n",
    "\n",
    "    Args:\n",
    "        time (np.ndarray): array with timestamps\n",
    "        series (np.ndarray): array with values of the time series\n",
    "\n",
    "    Returns:\n",
    "        (np.ndarray, np.ndarray, np.ndarray, np.ndarray): tuple containing timestamp and \n",
    "                                                          series values for train and validation\n",
    "    \"\"\"\n",
    "    ### START CODE HERE ###\n",
    "    # Get train split\n",
    "    time_train = None\n",
    "    series_train = None\n",
    "    # Get validation split\n",
    "    time_valid = None\n",
    "    series_valid = None\n",
    "    ### END CODE HERE ###\n",
    "\n",
    "    return time_train, series_train, time_valid, series_valid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 759
    },
    "deletable": false,
    "editable": false,
    "id": "gwwAas-sYMLN",
    "outputId": "55fcf156-416f-40a8-f59f-c350ce65b43d",
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Get your train and validation splits\n",
    "time_train, series_train, time_valid, series_valid = train_val_split(TIME, SERIES)\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(time_train, series_train, title=\"Training\")\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(time_valid, series_valid, title=\"Validation\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "<table><tr><td><img src='images/train_series.png' ></td><td><img src='images/val_series.png'></td></tr></table>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Test your code!\n",
    "unittests.test_train_val_split(train_val_split)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Evaluation Metrics\n",
    "\n",
    "### Exercise 2: compute_metrics\n",
    "\n",
    "Now that you have successfully split the data into training and validation sets you will need a way of knowing how good your forecasts are. For this complete the `compute_metrics` below. This function receives the true series and the forecast and returns the `mse` and the `mae` between the two curves.  You should use functions provided by [`tf.keras.losses`](https://www.tensorflow.org/api_docs/python/tf/keras/losses) to compute MSE and MAE errors.\n",
    "\n",
    "**Notice that this function does not receive any time (x coordinate) data since it assumes that both series will have the same values for the x coordinate**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "id": "2bzRtn779WoJ",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# GRADED FUNCTION: compute_metrics\n",
    "def compute_metrics(true_series, forecast):\n",
    "    \"\"\"compute mean squared error and mean absolute error for predictions\n",
    "\n",
    "    Args:\n",
    "        true_series (np.ndarray): original (true) series\n",
    "        forecast (np.ndarray): forecast series\n",
    "\n",
    "    Returns:\n",
    "        (np.float64, np.float64): MSE and MAE\n",
    "    \"\"\"\n",
    "    ### START CODE HERE ###\n",
    "    mse = None\n",
    "    mae = None\n",
    "    ### END CODE HERE ###\n",
    "\n",
    "    return mse, mae"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "deletable": false,
    "editable": false,
    "id": "Hv9xAPhvxbJD",
    "outputId": "37931ee0-ef56-4fa4-bfb6-6287b20dd08f",
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Try out your function\n",
    "\n",
    "# Define some dummy series for testing\n",
    "zeros = np.zeros(5)\n",
    "ones = np.ones(5)\n",
    "\n",
    "mse, mae = compute_metrics(zeros, ones)\n",
    "print(f\"mse: {mse}, mae: {mae} for series of zeros and prediction of ones\\n\")\n",
    "\n",
    "mse, mae = compute_metrics(ones, ones)\n",
    "print(f\"mse: {mse}, mae: {mae} for series of ones and prediction of ones\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "mse: 1.0, mae: 1.0 for series of zeros and prediction of ones\n",
    "\n",
    "mse: 0.0, mae: 0.0 for series of ones and prediction of ones\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Test your code!\n",
    "unittests.test_compute_metrics(compute_metrics)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "bjD8ncEZbjEW"
   },
   "source": [
    "# Forecasting\n",
    "\n",
    "Now that you have a way of measuring the performance of your forecasts it is time to actually start doing some forecasts. Your goal is to predict the values in the validation set.\n",
    "\n",
    "Let's start easy by using a naive forecast.\n",
    "\n",
    "## Naive Forecast\n",
    "\n",
    "### Exercise 3: naive_forecast\n",
    "\n",
    "Define the `naive_forecast` variable below. Remember that the naive forecast simply takes the last value to predict the next one. This means that the forecast series should be identical to the validation series but delayed one time step. \n",
    "\n",
    "**Hint:**\n",
    "\n",
    "**You need to pass the correct elements of the original series `SERIES` to compute the `naive_forecast`. Here are a few things to keep in mind:**\n",
    "\n",
    "- To make the forecast for the first element in the validation set you need the value of the very last element on the train set\n",
    "- You should leave out the last element, since the forecast obtained using this value does not exists in the validation set and you will not be able to compute the evaluation metrics if this element is kept."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# GRADED VARIABLE\n",
    "### START CODE HERE ###\n",
    "naive_forecast = None #get naive forecast\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Look into naive_forecast\n",
    "print(f\"validation series has shape: {series_valid.shape}\\n\")\n",
    "print(f\"naive forecast has shape: {naive_forecast.shape}\\n\")\n",
    "print(f\"comparable with validation series: {series_valid.shape == naive_forecast.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "validation series has shape: (361,)\n",
    "\n",
    "naive forecast has shape: (361,)\n",
    "\n",
    "comparable with validation series: True\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Plot the validation data and the naive forecast\n",
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(time_valid, series_valid, label=\"validation set\")\n",
    "plot_series(time_valid, naive_forecast, label=\"naive forecast\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "<div>\n",
    "<img src=\"images/naive.png\" width=\"650\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "fw1SP5WeuixH"
   },
   "source": [
    "Let's zoom in on the end of the validation period:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(time_valid, series_valid, start=330, end=361, label=\"validation set\")\n",
    "plot_series(time_valid, naive_forecast, start=330, end=361, label=\"naive forecast\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "<div>\n",
    "<img src=\"images/naive_zoom.png\" width=\"650\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "35gIlQLfu0TT"
   },
   "source": [
    "**You should see that the naive forecast lags 1 step behind the time series and that both series end on the same time step.**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Uh_7244Gsxfx"
   },
   "source": [
    "Now let's compute the mean squared error and the mean absolute error between the forecasts and the predictions in the validation period:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "deletable": false,
    "editable": false,
    "id": "byNnC7IbsnMZ",
    "outputId": "63aa5d88-bdbe-471e-c762-b8ff806ceb8c",
    "tags": []
   },
   "outputs": [],
   "source": [
    "mse, mae = compute_metrics(series_valid, naive_forecast)\n",
    "\n",
    "print(f\"mse: {mse:.2f}, mae: {mae:.2f} for naive forecast\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "mse: 19.58, mae: 2.60 for naive forecast\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Test your code!\n",
    "unittests.test_naive_forecast(naive_forecast)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "WGPBC9QttI1u"
   },
   "source": [
    "That's our baseline, now let's try a moving average.\n",
    "\n",
    "## Moving Average\n",
    "\n",
    "### Exercise 4: moving_average_forecast\n",
    "\n",
    "Complete the `moving_average_forecast` function below. This function receives a `series` and a `window_size` and computes the moving average forecast for every point after the initial `window_size` values.\n",
    "\n",
    "**This function should receive the complete `SERIES` and, just for this exercise, you will get the prediction for all the `SERIES`. The returned prediction will then be sliced to match the validation period, so your function doesn't need to account for matching the series to the validation period.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "id": "YGz5UsUdf2tV",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# GRADED FUNCTION: moving_average_forecast\n",
    "def moving_average_forecast(series, window_size):\n",
    "    \"\"\"Forecasts the mean of the last few values.\n",
    "        If window_size=1, then this is equivalent to naive forecast\n",
    "\n",
    "    Args:\n",
    "        series (np.ndarray): time series\n",
    "        window_size (int): window size for the moving average forecast\n",
    "\n",
    "    Returns:\n",
    "        np.ndarray: time series forcast\n",
    "    \"\"\"\n",
    "    \n",
    "    forecast = []\n",
    "    \n",
    "    ### START CODE HERE ###\n",
    "    for time in None:\n",
    "        forecast.append(None)\n",
    "        \n",
    "    # Convert to a numpy array.\n",
    "    np_forecast = None\n",
    "    \n",
    "    ### END CODE HERE ###\n",
    "    \n",
    "    return np_forecast"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You cannot compute the moving average for the first `window_size` values since there aren't enough values to compute the desired average. So if you use the whole `SERIES` and a `window_size` of 50 your function should return a series with the number of elements equal to:\n",
    "\n",
    "```python\n",
    "len(SERIES) - 50\n",
    "````"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "print(f\"Whole SERIES has {len(SERIES)} elements so the moving average forecast should have {len(SERIES)-50} elements\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 388
    },
    "deletable": false,
    "editable": false,
    "id": "HHFhGXQji7_r",
    "outputId": "232dfd1d-05f5-4ce1-e090-c612c64c71ca",
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Try out your function\n",
    "moving_avg = moving_average_forecast(SERIES, window_size=WINDOW_SIZE)\n",
    "print(f\"moving average forecast with whole SERIES has shape: {moving_avg.shape}\\n\")\n",
    "\n",
    "# Slice it so it matches the validation period\n",
    "moving_avg = moving_avg[1100 - WINDOW_SIZE:]\n",
    "print(f\"moving average forecast after slicing has shape: {moving_avg.shape}\\n\")\n",
    "print(f\"comparable with validation series: {series_valid.shape == moving_avg.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "moving average forecast with whole SERIES has shape: (1411,)\n",
    "\n",
    "moving average forecast after slicing has shape: (361,)\n",
    "\n",
    "comparable with validation series: True\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(time_valid, series_valid)\n",
    "plot_series(time_valid, moving_avg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected output:**\n",
    "<div>\n",
    "<img src=\"images/moving_avg.png\" width=\"650\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "deletable": false,
    "editable": false,
    "id": "oINy178C_cCv",
    "outputId": "7917e7e3-460f-41b8-866a-6cf560e78fd1",
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Compute evaluation metrics\n",
    "mse, mae = compute_metrics(series_valid, moving_avg)\n",
    "\n",
    "print(f\"mse: {mse:.2f}, mae: {mae:.2f} for moving average forecast\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "mse: 56.80, mae: 4.12 for moving average forecast\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Test your code!\n",
    "unittests.test_moving_average_forecast(moving_average_forecast)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "JMYPnJqwz8nS"
   },
   "source": [
    "That's worse than naive forecast! The moving average does not anticipate trend or seasonality, so let's try to remove them by using differentiation. \n",
    "\n",
    "## Differencing\n",
    "\n",
    "### Exercise 5: diff_series\n",
    "\n",
    "Since the seasonality period is 365 days, we will subtract the value at time *t* – 365 from the value at time *t*.\n",
    "\n",
    "Define the `diff_series` and `diff_time` variables below to achieve this. Notice that `diff_time` is the values of the x-coordinate for `diff_series`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 388
    },
    "deletable": false,
    "id": "5pqySF7-rJR4",
    "outputId": "7822b126-b20a-4c0d-ec2f-254d033f9df6",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# GRADED VARIABLES\n",
    "### START CODE HERE ###\n",
    "# Differentiate the series. Use a differentiation step according to the series seasonality\n",
    "diff_series = None\n",
    "# Get the appropiate time indexes\n",
    "diff_time = None\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "print(f\"Whole SERIES has {len(SERIES)} elements so the differencing should have {len(SERIES)-365} elements\\n\")\n",
    "print(f\"diff series has shape: {diff_series.shape}\\n\")\n",
    "print(f\"x-coordinate of diff series has shape: {diff_time.shape}\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "```\n",
    "Whole SERIES has 1461 elements so the differencing should have 1096 elements\n",
    "\n",
    "diff series has shape: (1096,)\n",
    "\n",
    "x-coordinate of diff series has shape: (1096,)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(diff_time, diff_series)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected output:**\n",
    "\n",
    "<div>\n",
    "<img src=\"images/diff.png\" width=\"650\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Test your code!\n",
    "unittests.test_diff_series(diff_series)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "xPlPlS7DskWg"
   },
   "source": [
    "### Exercise 6: diff_moving_average\n",
    "\n",
    "Great, the trend and seasonality seem to be gone, so now we can use the moving average.\n",
    "\n",
    "Define the `diff_moving_avg` variable. \n",
    "\n",
    "**Notice that the `window_size` has already being defined and that you will need to perform the correct slicing for the series to match the validation period.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 388
    },
    "deletable": false,
    "id": "QmZpz7arsjbb",
    "outputId": "81bfe164-0d5e-452e-ecc5-eb21bb71097f",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# GRADED VARIABLE\n",
    "### START CODE HERE ###\n",
    "\n",
    "# Apply the moving avg to diff series. Use a correct window_size \n",
    "diff_moving_avg = moving_average_forecast(None, None)\n",
    "\n",
    "# Perform the correct slicing\n",
    "diff_moving_avg = diff_moving_avg[None:]\n",
    "\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "print(f\"moving average forecast with diff series after slicing has shape: {diff_moving_avg.shape}\\n\")\n",
    "print(f\"comparable with validation series: {series_valid.shape == diff_moving_avg.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "```\n",
    "moving average forecast with diff series after slicing has shape: (361,)\n",
    "\n",
    "comparable with validation series: True\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(time_valid, diff_series[1100 - 365:])\n",
    "plot_series(time_valid, diff_moving_avg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected output:**\n",
    "\n",
    "<div>\n",
    "<img src=\"images/diff_moving.png\" width=\"650\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Test your code!\n",
    "unittests.test_diff_moving_avg(diff_moving_avg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Gno9S2lyecnc"
   },
   "source": [
    "### Exercise 7: diff_moving_avg_plus_past\n",
    "\n",
    "Now let's bring back the trend and seasonality by adding the past values from t – 365. For each value you want to forecast, you will be adding the exact same point, but from the previous cycle in the original time series. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 388
    },
    "deletable": false,
    "id": "Dv6RWFq7TFGB",
    "outputId": "f2db4f8e-0212-4bdb-ad05-af071b147f6e",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# GRADED VARIABLES\n",
    "### START CODE HERE ###\n",
    "\n",
    "# Slice the whole SERIES to get the past values. \n",
    "# You want to get the value from the previous period for each forecasted value\n",
    "past_series = SERIES[None:None]\n",
    "\n",
    "# Add the past to the moving average of diff series\n",
    "diff_moving_avg_plus_past = past_series + None\n",
    "\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "print(f\"past series has shape: {past_series.shape}\\n\")\n",
    "print(f\"moving average forecast with diff series plus past has shape: {diff_moving_avg_plus_past.shape}\\n\")\n",
    "print(f\"comparable with validation series: {series_valid.shape == diff_moving_avg_plus_past.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "past series has shape: (361,)\n",
    "\n",
    "moving average forecast with diff series plus past has shape: (361,)\n",
    "\n",
    "comparable with validation series: True\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(time_valid, series_valid)\n",
    "plot_series(time_valid, diff_moving_avg_plus_past)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected output:**\n",
    "\n",
    "<div>\n",
    "<img src=\"images/plus_past.png\" width=\"650\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Compute evaluation metrics\n",
    "mse, mae = compute_metrics(series_valid, diff_moving_avg_plus_past)\n",
    "\n",
    "print(f\"mse: {mse:.2f}, mae: {mae:.2f} for moving average plus past forecast\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "mse: 8.50, mae: 2.33 for moving average plus past forecast\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Test your code!\n",
    "unittests.test_diff_moving_avg_plus_past(diff_moving_avg_plus_past)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vx9Et1Hkeusl"
   },
   "source": [
    "Better than naive forecast, good. However the forecasts look a bit too random, because we're just adding past values, which were noisy. \n",
    "\n",
    "### Exercise 8: smooth_past_series\n",
    "\n",
    "Let's use a moving averaging on **past** values to remove some of the noise. Use a `window_size=10` for this smoothing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 388
    },
    "deletable": false,
    "id": "K81dtROoTE_r",
    "outputId": "8c2b96f4-1026-42e5-dce3-29475f5610d1",
    "tags": [
     "graded"
    ]
   },
   "outputs": [],
   "source": [
    "# GRADED VARIABLE\n",
    "### START CODE HERE ###\n",
    "# Perform the correct split of SERIES, remember to use a window_size=10\n",
    "smooth_past_series = moving_average_forecast(SERIES[None:None], None)\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "print(f\"smooth past series has shape: {smooth_past_series.shape}\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Add the smoothed out past values to the moving avg of diff series\n",
    "diff_moving_avg_plus_smooth_past = smooth_past_series + diff_moving_avg\n",
    "\n",
    "print(f\"moving average forecast with diff series plus past has shape: {diff_moving_avg_plus_smooth_past.shape}\\n\")\n",
    "print(f\"comparable with validation series: {series_valid.shape == diff_moving_avg_plus_smooth_past.shape}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "moving average forecast with diff series plus past has shape: (361,)\n",
    "\n",
    "comparable with validation series: True\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "plot_series(time_valid, series_valid)\n",
    "plot_series(time_valid, diff_moving_avg_plus_smooth_past)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected output:**\n",
    "\n",
    "<div>\n",
    "<img src=\"images/plus_smooth.png\" width=\"650\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Compute evaluation metrics\n",
    "mse, mae = compute_metrics(series_valid, diff_moving_avg_plus_smooth_past)\n",
    "\n",
    "print(f\"mse: {mse:.2f}, mae: {mae:.2f} for moving average plus smooth past forecast\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Expected Output:**\n",
    "\n",
    "```\n",
    "mse: 12.53, mae: 2.20 for moving average plus smooth past forecast\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [],
   "source": [
    "# Test your code!\n",
    "unittests.test_smooth_past_series(smooth_past_series)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d3_54UQCdPuP"
   },
   "source": [
    "**Congratulations on finishing this week's assignment!**\n",
    "\n",
    "You have successfully implemented functions for time series splitting and evaluation while also learning how to deal with time series data and how to code forecasting methods!\n",
    "\n",
    "**Keep it up!**"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "C4W1_Assignment_Solution.ipynb",
   "provenance": []
  },
  "grader_version": "1",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
